package com.joinway.framework.admin.core.plugin.service;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.joinway.framework.admin.bean.domain.AdminRole;
import com.joinway.framework.admin.bean.domain.AdminUser;
import com.joinway.framework.admin.bean.domain.AdminUserRole;
import com.joinway.framework.admin.bean.domain.AdminUserVt;
import com.joinway.framework.admin.core.bean.DataRecord;
import com.joinway.framework.admin.core.service.AdminQueryService;
import com.joinway.framework.admin.core.service.table.TableService;
import com.joinway.framework.bean.logging.annotation.InputLog;
import com.joinway.framework.bean.logging.annotation.OutputLog;
import com.joinway.framework.bean.view.View;
import com.joinway.framework.data.jdbc.repository.TableRepository;
import com.joinway.framework.extension.cipher.MD5;
import com.joinway.framework.extension.groovy.DomainUtils;
import com.joinway.framework.extension.groovy.GroovyUtils;
import com.joinway.framework.extension.utils.NumberUtils;

@Service
public class AdminUserTableService extends TableService {

	private final static Logger log = LoggerFactory.getLogger(AdminUserTableService.class);
	
	public static final String ROLE_IDS_KEY = "roleIds";
	
	@Autowired TableRepository repository;
	
	@Autowired AdminQueryService queryService;
	
	@Override
	public String getTableName() {
		return "adminUser";
	}

	@Transactional(rollbackFor=Throwable.class)
	@Override
	@InputLog
	@OutputLog
	public View save(String table, String idFieldName, Map<String, String> params) throws Exception {
		AdminUser target = super.getDomainEntity(params, AdminUser.class);
		AdminUser source = repository.findById(AdminUser.class, params.get(idFieldName));
		
		if(source != null){
			// update user
			if(StringUtils.isNotBlank(target.getPassword())){
				// change password
				target.setPassword(MD5.encrypt(target.getPassword(), target.getLoginName().toLowerCase()));
			}else{
				// keep password
				target.setPassword(source.getPassword());
			}
		}else{
			// add user
			target.setPassword(MD5.encrypt(target.getPassword(), target.getLoginName().toLowerCase()));
		}
		
		repository.save(target);
		
		int userId = NumberUtils.convertToInt(params.get(idFieldName));
		List<AdminUserRole> adminUserRoles = queryService.findAdminUserRoles(userId);
		
		List<Integer> primaryKeys = new LinkedList<>();
		if(CollectionUtils.isNotEmpty(adminUserRoles)){
			adminUserRoles.forEach(r -> primaryKeys.add(r.getId()));
		}
		
		String ids = StringUtils.join(primaryKeys, ",");
		repository.delete("delete from admin_user_role where id in (?)", ids);
//		repository.delete("delete from admin_user_role where user_id = ?", target.getId());
		
		String[] roleIds = StringUtils.trimToEmpty(params.get(ROLE_IDS_KEY)).split(",");
		if(ArrayUtils.isNotEmpty(roleIds)){
			for(String id : roleIds){
				if(StringUtils.isNotBlank(id)){
					AdminUserRole userRole = new AdminUserRole();
					userRole.setRoleId(Integer.valueOf(id));
					userRole.setUserId(target.getId());
					
					repository.save(userRole);
				}
			}
		}
		
		return new View();
	}

	@Override
	@InputLog
	@OutputLog
	public DataRecord find(String table, String query, Integer page, Integer rows, Map params) throws Exception {
		DataRecord record = super.find(table, query, page, rows, params);
		//log.debug("data record is -> {}", record);
		
		List<AdminUserVt> newRows = new ArrayList<>();
		
		if(CollectionUtils.isNotEmpty(record.getDomains())){
			List<AdminUserRole> userRoles = repository.findAll(AdminUserRole.class);
			List<AdminRole> roles = repository.findAll(AdminRole.class);
			
			for(Object user : record.getDomains()){
				AdminUserVt vt = DomainUtils.convert(user, AdminUserVt.class);
				
//				int userId = user."getId"();
				int userId = NumberUtils.convertToInt(GroovyUtils.getProperty(user, "id"));
				List<String> roleNames = new LinkedList<>();
				
				for(AdminUserRole it : userRoles){
					if(it.getUserId() == userId){
						int roleId = it.getRoleId();
						Optional<AdminRole> optional = roles.stream().filter(r -> it.getRoleId() == r.getId()).findFirst();
						AdminRole role = optional.isPresent() ? optional.get() : null;
						
						if(role != null){
							roleNames.add(role.getRoleName());
						}else{
							log.error("no role id {} was found", roleId);
						}
					}
				}
				
				vt.setRoleNames(StringUtils.join(roleNames, ","));
				
				newRows.add(vt);
			}
			
		}
		
		DataRecord curRecord = new DataRecord();
		curRecord.setDomains(newRows);
		curRecord.setCount(record.getCount());
		
		return curRecord;
	}

}
